package com.meis.widget;

import com.meis.widget.utils.AttrUtils;
import com.meis.widget.utils.DensityUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PathMeasure;
import ohos.agp.utils.Color;
import ohos.app.Context;
import org.jetbrains.annotations.Nullable;

/**
 * desc:文字路径控件
 * author: wens
 * date: 2018/4/29.
 */
public class MeiTextPathView extends Component implements Component.DrawTask, Component.EstimateSizeListener {

    //绘画部分长度
    protected float mStop = 0;
    private Paint mPaint;
    //默认值为5
    private int mTextSize = 64;
    //文本宽度
    private float mTextWidth;
    //    private float mTextHeight;
    private int mTextColor = Color.RED.getValue();
    //文本
    private String mText = "MEI_S";
    private float mStrokeWidth = 5;
    private Path mDstPath;
    private PathMeasure mPathMeasure;
    private float mPathLength = 0;
    private float mCurrentLength = 0;
    private AnimatorValue mAnimation = null;

    //动画是否循环
    private boolean mIsCycle;

    //动画时长
    private int mDuration = 6000;

    //是否自动开始
    private boolean mAutoStart;
    //字母数组
    private String[] chars;
    //单个字母的path的长度
    private float[] charLength;

    private Path[] singlePaths;

    private Paint.FontMetrics metrics;

    public MeiTextPathView(Context context) {
        this(context, null);
    }

    public MeiTextPathView(Context context, @Nullable AttrSet attrs) {
        this(context, attrs, "");
    }

    public MeiTextPathView(Context context, @Nullable AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mText = AttrUtils.getStringFromAttr(attrs, "text", "");
        mTextSize = AttrUtils.getDimensionFromAttr(attrs, "textSize", 108);
        mTextColor = AttrUtils.getColorFromAttr(attrs, "textColor", Color.RED.getValue());
        mDuration = AttrUtils.getIntegerFromAttr(attrs, "duration", 6000);
        mStrokeWidth = AttrUtils.getDimensionFromAttr(attrs, "strokeWidth", 5);
        mIsCycle = AttrUtils.getBooleanFromAttr(attrs, "cycle", false);
        mAutoStart = AttrUtils.getBooleanFromAttr(attrs, "autoStart", true);

        init();
        initTextPath();

        setEstimateSizeListener(this);
        addDrawTask(this);
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(mTextSize);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setColor(new Color(mTextColor));
        mPaint.setStrokeWidth(mStrokeWidth);

        mDstPath = new Path();
        mPathMeasure = new PathMeasure(new Path(), false);
    }

    //初始化文字路径
    private void initTextPath() {
        mPathLength = 0;
        mDstPath.reset();

        if (null == mText || mText.equals("")) {
            mText = "mei_s";
        }

        mTextWidth = mPaint.getTextBounds(mText).getWidth();
        metrics = mPaint.getFontMetrics();
//        mTextHeight = metrics.bottom - metrics.top;

        initSingleText();

        if (mAutoStart) {
            getContext().getUITaskDispatcher().asyncDispatch(this::startAnimation);
        }
    }

    private void initSingleText() {
        chars = mText.split("");
        charLength = new float[chars.length];
        singlePaths = new Path[chars.length];
        int offset = 0;
        for (int i = 0; i < chars.length; i++) {
            Path singlePath = new Path();

            if (i > 0) {
                int width = mPaint.getTextBounds(chars[i - 1]).getWidth();
                offset += width + 20; //字符之间间距20个像素
            }

            mPaint.addTextToPath(chars[i], offset, -metrics.ascent, singlePath);
            mPathMeasure.setPath(singlePath, false);
            charLength[i] = mPathMeasure.getLength();
            singlePaths[i] = singlePath;

            mPathLength += charLength[i];
        }
    }

    /**
     * 开始动画
     */
    public void startAnimation() {
        if (mAnimation == null) {
            mAnimation = new AnimatorValue();
        }
        if (mAnimation.isRunning()) return;
        if (mIsCycle) {
            mAnimation.setLoopedCount(Animator.INFINITE);
        } else {
            mAnimation.setLoopedCount(0);
        }
        mAnimation.setDuration(mDuration);
        mAnimation.setValueUpdateListener((animatorValue, v) -> {
            mCurrentLength = v * mPathLength;
            invalidate();
        });
        mAnimation.start();
    }

    /**
     * 停止动画
     */
    public void stopAnimation() {
        if (mAnimation != null && mAnimation.isRunning())
            mAnimation.cancel();
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = EstimateSpec.getMode(widthMeasureSpec);
        int heightMode = EstimateSpec.getMode(heightMeasureSpec);
        int widthSize = EstimateSpec.getSize(widthMeasureSpec);
        int heightSize = EstimateSpec.getSize(heightMeasureSpec);
        //处理包裹内容的情况
        int warpDefaultSize = DensityUtil.dp2px(getContext(), 100);

        if (widthMode == EstimateSpec.NOT_EXCEED && heightMode == EstimateSpec.NOT_EXCEED) {
            widthSize = heightSize = warpDefaultSize;
        } else if (widthMode == EstimateSpec.NOT_EXCEED) {
            widthSize = warpDefaultSize;
        } else if (heightMode == EstimateSpec.NOT_EXCEED) {
            heightSize = warpDefaultSize;
        }
        setEstimatedSize(widthSize, heightSize);
        return false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.save();
        mDstPath.reset();
        mStop = mCurrentLength;
        //在中间绘制
        canvas.translate(getWidth() / 2 - mTextWidth / 2, 0);
//        canvas.translate(0, getHeight() / 2 - mTextHeight / 2);

        drawSingle(canvas, mStop, 0);
        canvas.restore();
    }

    private void drawSingle(Canvas canvas, float stop, int i) {
        if (i < charLength.length) {
            mPathMeasure.setPath(singlePaths[i], false);
            mStop = mStop - charLength[i];
            mPathMeasure.getSegment(0, stop, mDstPath, true);
            canvas.drawPath(mDstPath, mPaint);

            drawSingle(canvas, mStop, i + 1);
        }
    }

    public int getTextSize() {
        return mTextSize;
    }

    /**
     * 设置画笔宽度
     *
     * @param size 画笔宽度
     * @return MeiTextPathView
     */
    public MeiTextPathView setTextSize(int size) {
        this.mTextSize = size;
        this.mPaint.setTextSize(mTextSize);
        return this;
    }

    public int getTextColor() {
        return mTextColor;
    }

    /**
     * 设置画笔颜色
     *
     * @param color 颜色
     * @return MeiTextPathView
     */
    public MeiTextPathView setTextColor(int color) {
        this.mTextColor = color;
        this.mPaint.setColor(new Color(mTextColor));
        return this;
    }

    public String getText() {
        return mText;
    }

    /**
     * 设置绘制的文本
     *
     * @param text 文本
     * @return MeiTextPathView
     */
    public MeiTextPathView setText(String text) {
        this.mText = text;
        this.initTextPath();
        return this;
    }

    public float getStrokeWidth() {
        return mStrokeWidth;
    }

    /**
     * 设置描边宽度
     *
     * @param width 宽度
     * @return MeiTextPathView
     */
    public MeiTextPathView setStrokeWidth(int width) {
        this.mStrokeWidth = width;
        this.mPaint.setStrokeWidth(mStrokeWidth);
        return this;
    }

    public int getDuration() {
        return mDuration;
    }

    /**
     * 设置动画时长
     *
     * @param duration 时长
     * @return MeiTextPathView
     */
    public MeiTextPathView setDuration(int duration) {
        this.mDuration = duration;
        return this;
    }

    public boolean isCycle() {
        return mIsCycle;
    }

    //是否循环
    public MeiTextPathView setCycle(boolean cycle) {
        this.mIsCycle = cycle;
        return this;
    }

    public boolean isAutoStart() {
        return mAutoStart;
    }

    //是否自动开始
    public MeiTextPathView setAutoStart(boolean autoStart) {
        this.mAutoStart = autoStart;
        return this;
    }
}
